package jp.yyoo.guitertuner;

import jp.yyoo.signalfilter.FirFilter;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.AudioRecord.OnRecordPositionUpdateListener;
import android.media.MediaRecorder;
import android.util.Log;

public class MainProgram {
	
	
	private Context ctx;
	
	
	
	private AudioRecord rec;
	
	private static final String TAG = "MainProgram";
	
	
	public static final int SAMPLING_RATE = 44100 / 1; //48000;
	
	public static final int frame_size = 256*2;
	
	private ProgramThread thread;
	
	public MainProgram( Context ctx_ ) {
		ctx = ctx_;
		
		thread = new ProgramThread( this );
		thread.start();
		
		
	}

	public void start() {

		// 1sample = 16bit = 2byte
		int input_buff_size_bytes = AudioRecord.getMinBufferSize( SAMPLING_RATE,
									AudioFormat.CHANNEL_CONFIGURATION_MONO,
									AudioFormat.ENCODING_PCM_16BIT );
		rec = new AudioRecord( MediaRecorder.AudioSource.MIC,
					SAMPLING_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO,
					AudioFormat.ENCODING_PCM_16BIT, input_buff_size_bytes * 4 );
		
		int input_buff_size = input_buff_size_bytes / 2;

		
		if ( frame_size > input_buff_size ) {
			Log.e(TAG, "frameSize is oversized");
		}
		

		//rec.setPositionNotificationPeriod( frame_size >> 1 );
		
		
		rec.setRecordPositionUpdateListener( thread );
		
		
		rec.startRecording();
		
		thread.startReading();
		
	}
	
	public void stop () {

		thread.stopReading();
		rec.stop();
		
		rec.release();
		
		rec = null;
		
	}
	
	short[] tmpBuffer = new short[frame_size];
	
	double[] parameter = { 
			1.722514773564070e-01 ,
			2.726465754185227e-01 ,
			2.812976004440336e-01 ,
			2.726465754185227e-01 ,
			1.722514773564070e-01
			
			};
	int paramLength = 5;
	FirFilter lowPass = new FirFilter( parameter );
	
	public void onRead( short[] buffer ) {
		/*
		callback.onReadCallback( buffer );
		return;
		*/
		
		short[] tmpBuffer = new short[ frame_size * 2 ];
		
		short[] buf = new short[ paramLength*2 ];
		int length = paramLength;
		int index = 0;
		
		for( int k = 0; k < frame_size; k++ ) {
			short in = buffer[k];
			float out;
			
			buf[index] = in;
			buf[index+length] = in;
			index = index+1;
			if ( index == length ) index = 0;
			out = 0;
			for (int i = 0; i < length; i++ )
				out += ( parameter[i] * buf[ index + i ]);
			
			tmpBuffer[k] = (short)( out );
		}
		
		callback.onReadCallback( tmpBuffer );
		
	}
	
	// fast FIR filter function
	private float fastFIR( float in, float coef[], float buf[], int index, int length ) {
		float out;
		int i;
		
		buf[index]=in;
		buf[index+length]=in;
		index = index+1;
		if ( index == length ) index = 0;
		out = 0;
		for (i = 0; i < length; i++ )
			out = out + coef[i] * buf[ index + i ];
		
		return out;
	}
	
	Callback callback;
	
	public void setCallback ( Callback callback_ ) {
		callback = callback_;
	}
	
	public interface Callback {
		
		void onReadCallback( short[] buffer );
		
	}
	
	
	class ProgramThread extends Thread implements OnRecordPositionUpdateListener {
	
		
		private
			short[] inputBuffer = new short[frame_size];
		
			int decoded_bytes = 0;
			int encoded_size = 0;
			
			MainProgram program;
			
			boolean flag;
			
			Object mutex;
			
		
		ProgramThread ( MainProgram program_ ){
			
			program = program_;
			flag = false;
			
			mutex = this;
		}
		
		void startReading() {
			if( flag ) return;
			
			flag = true;
			
			synchronized (mutex) {
				mutex.notifyAll();
			}
		}
		
		void stopReading() {
			if( !flag ) return;
			
			flag = false;
		}
		
		
		@Override
		public void run() {
			
			try {
				loop();
			} catch (Exception e) {
				Log.e( TAG, "error thread");
			}
		}
		
		private synchronized void loop() throws Exception{
			
			while( true ) {
				
				if( !flag ) mutex.wait();
				rec.read(inputBuffer, 0, frame_size);
				program.onRead( inputBuffer );
				
			}
		}
	
		public void onPeriodicNotification( AudioRecord recorder)
		{
			recorder.read(inputBuffer, 0, frame_size);
			
			program.onRead( inputBuffer );
			
		}
	
		public void onMarkerReached(AudioRecord recorder)
		{
		}
	}
}
